package momo.app.structure;

import java.util.AbstractList;
import java.util.NoSuchElementException;

public class SimpleCircularList<E> extends AbstractList<E>
{
	private int head, tail;
	private int size;
	private int capacity;
	private Object[] elements;
	
	public SimpleCircularList(int capacity)
	{
		if ( capacity <= 0 )
			throw new IllegalArgumentException();
		
		this.capacity = capacity;
		elements = new Object[capacity];
		size = 0;
		head = tail = 0;
	}
	
	synchronized public boolean add(E e)
	{
		if ( size != 0 && head == tail )
			head = (head+1)%capacity;
		
		elements[tail] = e;
		
		tail = (tail+1)%capacity;
		size = ++size>=capacity?capacity:size;
		
		return true;
	}

	synchronized public void clear()
	{
		elements = new Object[capacity];
		size = 0;
		head = tail = 0;
	}

	synchronized public boolean contains(Object o) {
		if ( indexOf(o) >= 0 )
			return true;
		return false;
	}

	synchronized public E get(int index)
	{
		if ( index < 0 || index >= size )
			throw new ArrayIndexOutOfBoundsException();
		
		index = (index+head)%capacity;
		return (E)elements[index];
	}
	
	synchronized public E firstElement()
	{
		if ( size == 0 )
			throw new NoSuchElementException();
		
		return this.get(0);
	}
	
	synchronized public E lastElement()
	{
		if ( size == 0 )
			throw new NoSuchElementException();
		
		return this.get(size-1);
	}

	synchronized public int indexOf(Object o) {
		if ( o == null )
			throw new NullPointerException();
		
		int counter = 0;
		while(counter < size)
		{
			int searchIndex = (counter+head)%capacity;
			if ( o.equals(elements[searchIndex]) )
				return counter;
			counter ++;
		}
		return -1;
	}

	synchronized public boolean isEmpty()
	{
		return ( size == 0 );
	}
	
	synchronized public boolean remove(Object o) {
		int index = indexOf(o);
		if ( index < 0 )
			return false;
		
		remove(index);
		return true;
	}

	synchronized public E remove(int index)
	{
		if ( index < 0 || index >= size )
			throw new ArrayIndexOutOfBoundsException();
		
		int limit = size-index;
		index = (index+head)%capacity;
		
		Object o = elements[index];
		
		int counter = 0;
		while(counter < limit)
		{
			int oldPos = (index+counter)%capacity;
			int newPos = (oldPos+1)%capacity;
			
			elements[oldPos] = elements[newPos];
			counter ++;
		}
		
		tail --;
		if ( tail < 0 )
			tail = capacity - 1;
		
		size --;
		
		return (E)o;
	}

	synchronized public E set(int index, E element)
	{
		if ( index < 0 || index >= size )
			throw new ArrayIndexOutOfBoundsException();
		
		E e = get(index);
		
		index = (index+head)%capacity;
		
		elements[index] = element;
		
		return e;
	}

	synchronized public int size()
	{
		return size;
	}
	
}//end of CircularList
